package com.scaffold.myproject.utils;

import cn.hutool.json.JSONUtil;
import com.scaffold.myproject.common.PageResult;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.SearchHit;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 通用 Elasticsearch 分页查询工具类
 * <p>
 * 支持任意索引、任意实体类型
 * 返回 PageResult<T> 统一分页结构
 *
 * @author lx
 * @date 2025/11/04
 */
@Slf4j
@Component
public class EsPageQueryUtil {

    @Resource
    private RestHighLevelClient client;

    /**
     * 通用分页查询方法
     *
     * @param index        索引名称
     * @param queryBuilder 查询条件（可为 BoolQueryBuilder、MatchQueryBuilder、RangeQueryBuilder 等）
     * @param pageNo       页码（从 1 开始）
     * @param pageSize     每页数量
     * @param sortField    排序字段（可为空）
     * @param sortOrder    排序方式（asc / desc，可为空）
     * @param clazz        反序列化目标类
     * @param <T>          泛型实体类型
     * @return PageResult<T> 分页结果
     * @throws IOException Elasticsearch 查询异常
     */
    public <T> PageResult<T> searchPage(
            String index,
            QueryBuilder queryBuilder,
            int pageNo,
            int pageSize,
            String sortField,
            String sortOrder,
            Class<T> clazz
    ) throws IOException {

        if (pageNo < 1) pageNo = 1;
        if (pageSize < 1) pageSize = 10;

        // 1 构建请求
        SearchRequest request = new SearchRequest(index);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        // 2 查询条件
        sourceBuilder.query(queryBuilder != null ? queryBuilder : new BoolQueryBuilder());

        // 3 分页参数
        sourceBuilder.from((pageNo - 1) * pageSize);
        sourceBuilder.size(pageSize);

        // 4 排序
        if (sortField != null && !sortField.isBlank()) {
            SortOrder order = "DESC".equalsIgnoreCase(sortOrder) ? SortOrder.DESC : SortOrder.ASC;
            sourceBuilder.sort(sortField, order);
        }

        // 5 组装请求
        request.source(sourceBuilder);

        //6 执行查询
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        // 7 解析响应结果
        long total = response.getHits().getTotalHits().value;
        List<T> records = Arrays.stream(response.getHits().getHits())
                .map(SearchHit::getSourceAsString)
                .map(json -> JSONUtil.toBean(json, clazz))
                .collect(Collectors.toList());

        log.debug("ES分页查询完成 => 索引: {}, 页码: {}, 条数: {}, 总数: {}", index, pageNo, records.size(), total);

        return new PageResult<>(records, (int) total, pageSize, pageNo);
    }
}
